// StringResourceProvider.cs
//
// Copyright (c) Sunday, July 27, 2008 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Linq;
using System.Windows;
using System.Windows.Data;

using Supremacy.Annotations;

using SupremacyEditor.Services;

namespace SupremacyEditor
{
    public class StringResourceProvider
	{
		#region Fields
		/// <summary>
        /// An attached property for assigning a default <see cref="StringResourceProvider"/> to an object.
		/// </summary>
		public static readonly DependencyProperty StringResourceProviderProperty;

		/// <summary>
        /// A resource key that can be used to manually store and retrieve a <see cref="StringResourceProvider"/>
        /// as a <see cref="ResourceDictionary"/> entry.
		/// </summary>
		public static readonly object StringResourceProviderResourceKey;

        private readonly ITextService _textService;
		#endregion

		#region Constructors
		/// <summary>
		/// Initializes the <see cref="StringResourceProvider"/> class.
		/// </summary>
		static StringResourceProvider()
		{
			StringResourceProviderResourceKey = new object();
			StringResourceProviderProperty = DependencyProperty.RegisterAttached(
				"StringResourceProvider",
				typeof(StringResourceProvider),
				typeof(StringResourceProvider),
				new FrameworkPropertyMetadata(
					null,
					FrameworkPropertyMetadataOptions.Inherits));
			StringResourceProviderProperty.AddOwner(typeof(UIElement));
		}

        /// <summary>
        /// Initializes a new instance of the <see cref="StringResourceProvider"/> class.
        /// </summary>
        /// <param name="textService">The localized text service.</param>
		public StringResourceProvider([NotNull] ITextService textService)
		{
		    if (textService == null)
		        throw new ArgumentNullException("textService");
		    _textService = textService;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the text lookup source used by this instance.
		/// </summary>
		public ITextService LookupText
		{
			get { return _textService; }
		}

		/// <summary>
		/// Gets the localized string with the specified key.
		/// </summary>
		/// <value></value>
		public string this[string key]
		{
			get { return _textService.GetClientString(key); }
		}
		#endregion

		#region Methods
		/// <summary>
        /// Determines whether the <see cref="StringResourceProvider"/> of a source object is inherited
        /// from an ancestor object.
		/// </summary>
		/// <param name="source">The source object.</param>
		/// <returns>
        /// <c>true</c> if the <see cref="StringResourceProvider"/> is inherited; otherwise, <c>false</c>.
		/// </returns>
		public static bool IsProviderInherited([NotNull] DependencyObject source)
		{
            if (source == null)
                throw new ArgumentNullException("source");
		    return Equals(
		        DependencyPropertyHelper.GetValueSource(
		            source,
		            StringResourceProviderProperty).BaseValueSource,
		        BaseValueSource.Inherited);
		}

		/// <summary>
		/// Binds the StringResourceProvider of the target object to that of the source object.
		/// </summary>
		/// <remarks>
        /// The primary use case for this function is to bind the <see cref="StringResourceProvider"/>
        /// of a child window to that of the owner window.  This is useful because WPF resources
        /// are not inherited via the owner-child window relationship, but there may be cases in
        /// which it is desirable for a child window to inherit the <see cref="StringResourceProvider"/>
        /// of its owner window.
		/// </remarks>
		/// <param name="source">The source object.</param>
		/// <param name="target">The target object.</param>
		public static void BindProvider([NotNull] DependencyObject source, [NotNull] DependencyObject target)
		{
			if (source == null)
				throw new ArgumentNullException("source");
			if (target == null)
				throw new ArgumentNullException("target");
		    BindingOperations.SetBinding(
		        target,
		        StringResourceProviderProperty,
		        new Binding
		        {
		            Source = source,
		            Path = new PropertyPath(StringResourceProviderProperty),
		            Mode = BindingMode.OneWay
		        });
		}

		/// <summary>
        /// Gets the <see cref="StringResourceProvider"/> for the target object.
		/// </summary>
		/// <param name="target">The target object.</param>
        /// <returns>The <see cref="StringResourceProvider"/>.</returns>
		public static StringResourceProvider GetProvider([NotNull] DependencyObject target)
		{
			if (target == null)
				throw new ArgumentNullException("target");
			return target.GetValue(StringResourceProviderProperty) as StringResourceProvider;
		}

		/// <summary>
		/// Clears the local value of the StringResourceProvider property on the target object.
		/// </summary>
		/// <param name="target">The target object.</param>
		public static void ClearProvider([NotNull] DependencyObject target)
		{
			if (target == null)
				throw new ArgumentNullException("target");
			target.ClearValue(StringResourceProviderProperty);
		}

		/// <summary>
		/// Sets the StringResourceProvider dependency property on the target object to
		/// the given value.
		/// </summary>
		/// <param name="target">The target object.</param>
		/// <param name="value">The value.</param>
		public static void SetProvider([NotNull] DependencyObject target, [CanBeNull] StringResourceProvider value)
		{
			if (target == null)
				throw new ArgumentNullException("target");
			target.SetValue(StringResourceProviderProperty, value);
		}

		/// <summary>
		/// Creates a localized text binding on the specifed property of the target object.
		/// </summary>
		/// <param name="target">The target object.</param>
		/// <param name="property">The property which should be bound.</param>
		/// <param name="key">The unique identifier of the string to be bound.</param>
		public static void SetTextBinding(
            [NotNull] DependencyObject target,
            [NotNull] DependencyProperty property,
            [NotNull] string key)
		{
			if (target == null)
				throw new ArgumentNullException("target");
			if (property == null)
				throw new ArgumentNullException("property");
			if (String.IsNullOrEmpty(key))
				throw new ArgumentException("value must be a non-empty string", "key");

			BindingOperations.SetBinding(target, property, CreateTextBinding(key));
		}

		/// <summary>
		/// Creates a localized text binding.
		/// </summary>
		/// <param name="key">The unique identifier of the string to be bound.</param>
		/// <returns>A localized text binding.</returns>
		internal static Binding CreateTextBinding([NotNull] string key)
		{
            if (String.IsNullOrEmpty(key))
                throw new ArgumentException("value must be a non-empty string", "key");
		    return new Binding
		           {
		               Path = new PropertyPath("(0)[" + key + "]", StringResourceProviderProperty),
		               RelativeSource = RelativeSource.Self,
		               Mode = BindingMode.OneWay
		           };
		}
	    #endregion
	}
}